package com.hongyi.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hongyi.common.framework.constant.CacheConstants;
import com.hongyi.common.framework.constant.UserConstans;
import com.hongyi.common.framework.exception.ServiceException;
import com.hongyi.common.framework.service.DictService;
import com.hongyi.common.framework.utils.StreamUtils;
import com.hongyi.common.framework.utils.bean.MapstructUtils;
import com.hongyi.common.framework.utils.string.StringUtils;
import com.hongyi.common.mybatis.page.PageData;
import com.hongyi.common.mybatis.page.PageQuery;
import com.hongyi.common.redis.utils.RedisUtils;
import com.hongyi.system.domain.SysDictData;
import com.hongyi.system.domain.SysDictType;
import com.hongyi.system.domain.dto.SysDictTypeDto;
import com.hongyi.system.domain.vo.SysDictDataVo;
import com.hongyi.system.domain.vo.SysDictTypeVo;
import com.hongyi.system.mapper.SysDictDataMapper;
import com.hongyi.system.mapper.SysDictTypeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Service;
import com.hongyi.system.service.ISysDictTypeService;

import java.util.*;
import java.util.stream.Collectors;


@Service
public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService {

    @Autowired
    private SysDictTypeMapper sysDictTypeMapper;

    @Autowired
    private SysDictDataMapper sysDictDataMapper;

    private LambdaQueryWrapper<SysDictType> buildQueryWrapper(SysDictTypeDto sysDictTypeDto) {

        LambdaQueryWrapper<SysDictType> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(sysDictTypeDto.getDictName()), SysDictType::getDictName, sysDictTypeDto.getDictName());
        lqw.like(StringUtils.isNotBlank(sysDictTypeDto.getDictType()), SysDictType::getDictType, sysDictTypeDto.getDictType());
        lqw.eq(StringUtils.isNotBlank(sysDictTypeDto.getStatus()), SysDictType::getStatus, sysDictTypeDto.getStatus());
        lqw.orderByAsc(SysDictType::getDictId);
        return lqw;
    }

    @Override
    public PageData<SysDictTypeVo> selectPageDictTypeList(SysDictTypeDto sysDictTypeDto, PageQuery pageQuery) {
        IPage<SysDictTypeVo> sysDictTypeVoIPage = sysDictTypeMapper.selectVoPage(pageQuery.build(), buildQueryWrapper(sysDictTypeDto));
        return PageData.success(sysDictTypeVoIPage);
    }

    /**
     * 根据条件分页查询字典类型
     *
     * @param sysDictTypeDto 字典类型信息
     * @return 字典类型集合信息
     */
    @Override
    public List<SysDictTypeVo> selectDictTypeList(SysDictTypeDto sysDictTypeDto) {
        return sysDictTypeMapper.selectVoList(buildQueryWrapper(sysDictTypeDto));
    }

    @Override
    public SysDictTypeVo selectDictTypeById(Long dictId) {
        return sysDictTypeMapper.selectVoById(dictId);
    }

    /**
     * 根据字典类型查询字典数据
     *
     * @param dictType 字典类型
     * @return 字典数据集合信息
     */
    @Override
    public List<SysDictDataVo> selectDictDataByType(String dictType) {
        return Collections.emptyList();
    }

    /**
     * 校验字典类型称是否唯一
     *
     * @param sysDictTypeDto 字典类型
     * @return 结果
     */
    @Override
    public String checkDictTypeUnique(SysDictTypeDto sysDictTypeDto) {
        boolean existResult = sysDictTypeMapper.exists(new LambdaQueryWrapper<SysDictType>()
                .eq(SysDictType::getDictType, sysDictTypeDto.getDictType())
                .ne(ObjectUtil.isNotNull(sysDictTypeDto.getDictId()), SysDictType::getDictId, sysDictTypeDto.getDictId()));
        return existResult ? UserConstans.NOT_UNIQUE : UserConstans.UNIQUE;
    }

    /**
     * 新增保存字典类型信息
     *
     * @param sysDictTypeDto 字典类型信息
     * @return 结果
     */
    @CachePut(cacheNames = CacheConstants.SYS_DICT, key = "#sysDictTypeDto.dictType")
    @Override
    public List<SysDictDataVo> insertDictType(SysDictTypeDto sysDictTypeDto) {
        SysDictType dict = MapstructUtils.convert(sysDictTypeDto, SysDictType.class);
        int row = sysDictTypeMapper.insert(dict);
        if (row > 0) {
            // 新增 type 下无 data 数据 返回空防止缓存穿透
            return new ArrayList<>();
        }
        throw new ServiceException("操作失败");
    }

    /**
     * 修改保存字典类型信息
     *
     * @param sysDictTypeDto 字典类型信息
     * @return 结果
     */
    @CachePut(cacheNames = CacheConstants.SYS_DICT, key = "#sysDictTypeDto.dictType")
    @Override
    public List<SysDictDataVo> updateDictType(SysDictTypeDto sysDictTypeDto) {
        SysDictType dict = MapstructUtils.convert(sysDictTypeDto, SysDictType.class);
        SysDictType oldDict = sysDictTypeMapper.selectById(Objects.requireNonNull(dict).getDictId());
        List<SysDictDataVo> sysDictDataVos = sysDictDataMapper.selectVoList(new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, oldDict.getDictType()));
        if (CollectionUtils.isNotEmpty(sysDictDataVos)) {
            sysDictDataMapper.update(null, new LambdaUpdateWrapper<SysDictData>()
                    .set(SysDictData::getDictType, dict.getDictType())
                    .eq(SysDictData::getDictType, oldDict.getDictType()));
            int row = sysDictTypeMapper.updateById(dict);
            if (row > 0) {
                RedisUtils.deleteObject(CacheConstants.GLOBAL_REDIS_KEY +CacheConstants.SYS_DICT +":"+ oldDict.getDictType());
                return sysDictDataMapper.selectVoList(new LambdaQueryWrapper<SysDictData>()
                        .eq(SysDictData::getDictType, dict.getDictType())
                        .orderByAsc(SysDictData::getDictSort));
            }
        } else {
            RedisUtils.deleteObject(CacheConstants.GLOBAL_REDIS_KEY +CacheConstants.SYS_DICT +":"+ oldDict.getDictType());
            int row = sysDictTypeMapper.updateById(dict);
            if (row > 0) {
                return new ArrayList<>();
            }
        }
        throw new ServiceException("操作失败");
    }

    /**
     * 批量删除字典信息
     *
     * @param dictIds 需要删除的字典ID
     */
    @Override
    public void deleteDictTypeByIds(Long[] dictIds) {
        for (Long dictId : dictIds) {
            SysDictType dictType = sysDictTypeMapper.selectById(dictId);
            if (sysDictDataMapper.exists(new LambdaQueryWrapper<SysDictData>()
                    .eq(SysDictData::getDictType, dictType.getDictType()))) {
                throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName()));
            }
            RedisUtils.deleteObject(CacheConstants.GLOBAL_REDIS_KEY +CacheConstants.SYS_DICT +":"+ dictType.getDictType());
        }
        sysDictTypeMapper.deleteBatchIds(Arrays.asList(dictIds));
    }

    /**
     * 根据所有字典类型
     *
     * @return 字典类型集合信息
     */
    @Override
    public List<SysDictTypeVo> selectDictTypeAll() {
        return sysDictTypeMapper.selectVoList();
    }

    /**
     * 清空缓存数据
     */
    @Override
    public void clearCache() {
        Collection<String> keys = RedisUtils.keys(CacheConstants.GLOBAL_REDIS_KEY + CacheConstants.SYS_DICT + ":*");
        RedisUtils.deleteObject(keys);
    }

    /**
     * 根据字典类型和字典值获取字典标签
     *
     * @param dictType  字典类型
     * @param dictValue 字典值
     * @param separator 分隔符
     * @return 字典标签
     */
    @Override
    public String getDictLabel(String dictType, String dictValue, String separator) {
        // 优先从本地缓存获取
        List<SysDictDataVo> datas  = (List<SysDictDataVo>)RedisUtils.getCacheObject(CacheConstants.SYS_DICT + dictType);
        if (ObjectUtil.isNull(datas)) {
            datas =  sysDictDataMapper.selectVoList(new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, dictType)
                    .orderByAsc(SysDictData::getDictSort));
            RedisUtils.setCacheObject(CacheConstants.SYS_DICT + dictType, datas);
        }
        Map<String, String> map = StreamUtils.toMap(datas, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel);
        if (StringUtils.containsAny(dictValue, separator)) {
            return Arrays.stream(dictValue.split(separator))
                    .map(v -> map.getOrDefault(v, StringUtils.EMPTY))
                    .collect(Collectors.joining(separator));
        } else {
            return map.getOrDefault(dictValue, StringUtils.EMPTY);
        }
    }

    /**
     * 根据字典类型和字典标签获取字典值
     *
     * @param dictType  字典类型
     * @param dictLabel 字典标签
     * @param separator 分隔符
     * @return 字典值
     */
    @Override
    public String getDictValue(String dictType, String dictLabel, String separator) {
        // 优先从本地缓存获取
        List<SysDictDataVo> datas  = (List<SysDictDataVo>)RedisUtils.getCacheObject(CacheConstants.SYS_DICT + dictType);
        if (ObjectUtil.isNull(datas)) {
            datas =  sysDictDataMapper.selectVoList(new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, dictType)
                    .orderByAsc(SysDictData::getDictSort));
            RedisUtils.setCacheObject(CacheConstants.SYS_DICT + dictType, datas);
        }
        Map<String, String> map = StreamUtils.toMap(datas, SysDictDataVo::getDictLabel, SysDictDataVo::getDictValue);
        if (StringUtils.containsAny(dictLabel, separator)) {
            return Arrays.stream(dictLabel.split(separator))
                    .map(l -> map.getOrDefault(l, StringUtils.EMPTY))
                    .collect(Collectors.joining(separator));
        } else {
            return map.getOrDefault(dictLabel, StringUtils.EMPTY);
        }
    }

    @Override
    public Map<String, String> getAllDictByDictType(String dictType) {
        return Collections.emptyMap();
    }
}
